from __future__ import division

import random

import numpy as np
import matplotlib.pyplot as plt
import math

minX = 0.0
maxX = 8.0

# 定义一个待解函数方程
def ObjFun(x):
    # y = x ** 3 - 40 * x ** 2 - 4 * x + 6
    y = 2*math.sin(3*x) + 4*math.cos(x)
    return y

# 生成在定义域[0,10]上，f(x)的函数图像
x = np.linspace(minX, maxX, 500,endpoint=True)
y = [0]*len(x)
for i in range(len(x)):
    y[i] = ObjFun(x[i])
min_index=np.argmin(y)
plt.xlim(0,10)
plt.plot(x, y)
plt.plot(min_index,y[min_index],'gs')
plt.annotate(f'x={min_index} y={y[min_index]}' ,xytext=(min_index,y[min_index]),xy=(min_index,y[min_index]))
plt.show()

sp_l,sp_r = -0.1,0.1
# 定义判断方法，判断是否要接受当前最优解.0-不接受 1-接受
def Judge(yNew, y, T):
    if yNew<y:
        return 1
    else:
        if math.exp(-(yNew - y) / T)>random.random():
            return 1
    return 0

#为当前解添加随机扰动
def Disturbance(x):
    xNew = x + np.random.uniform(low=sp_l, high=sp_r) * 2.0
    while (minX > xNew or xNew > maxX):
        xNew = x + np.random.uniform(low=sp_l, high=sp_r) * 2.0
    return xNew

#退火算法实现
def anneal(T,T1,Tmin,epochs,t,index):
    tmpX = [] # 存储每次最优解随机扰动后的值
    recordX = [] # 存储有效的最优解
    x = Disturbance(0)  # 随机初始化一个最优解
    while T >= Tmin:
        for i in range(epochs):
            # 计算y值
            y = ObjFun(x)
            # 使x在定义域内随机摆动
            xNew = Disturbance(x)
            tmpX.append(xNew)
            # 判断是否使用新的最优解
            if Judge(ObjFun(xNew), y, T) == 1:
                x = xNew
                recordX.append(ObjFun(x));

        # print(f'本次降温温度：{T},温度段最优解：{x},最小值：{ObjFun(x)}')
        T = T * t

    print(f'最优解：{x},最小值：{ObjFun(x)}')
    min_y = np.min(recordX)

    # plt.plot([i for i in range(len(tmpX))], tmpX, 'b', label='temporary-X')
    plt.subplot(2, 2, index + 1)
    plt.subplots_adjust(wspace=0.4, hspace=0.4)
    plt.ylim(-8, 8)
    plt.plot([i for i in range(len(recordX))], recordX, 'r', label='Min(Y)')
    # plt.annotate(recordX[index], xytext=(index, recordX[index] + 100), xy=(index, recordX[index]))
    plt.title(f'c={sp_l}-{sp_r},Min={round(min_y, 2)},Last={round(recordX[len(recordX)-1], 2)}')
    plt.legend()
    



for i in range(4):
    # Tarr = [1000, 100, 10, 5]
    Tmin = 1  # 设置初始温度,最小温度
    epochs = [100,50,10,1]  # 设置每一次降温后的执行次数
    t = [0.95,0.9,0.85,0.8]  # 降温函数
    sp = [[-1,1],[-0.5,0.5],[-0.1,0.1],[-0.01,0.01]]
    sp_l = sp[i][0]
    sp_r = sp[i][1]
    anneal(100,'',Tmin,10,0.9,i)
plt.show()



